﻿#include "NoticeDialog.h"
#include "../../MirGraphics/MLibrary.h"
#include "../../MirSounds/SoundManager.h"
#include "../../Forms/Client.CMain.h"
#include "../../../Shared/Functions/Functions.h"

using namespace Client::MirControls;
using namespace Client::MirGraphics;
using namespace Client::MirSounds;
using namespace Shared;

namespace Client::MirScenes::Dialogs
{

Regex *NoticeDialog::C = new Regex(R"({((.*?)\/(.*?))})");
Regex *NoticeDialog::L = new Regex(R"(\(((.*?)\/(.*?))\))");

    NoticeDialog::NoticeDialog()
    {
        setIndex(961);
        setLibrary(Libraries::Prguse);
        Point tempVar((Settings::ScreenWidth - getSize()->Width) / 2, (Settings::ScreenHeight - getSize()->Height) / 3);
        setLocation(&tempVar);
        TextLabel = std::vector<MirLabel*>(40);
        TextButtons = std::vector<MirLabel*>();

        MouseWheel += LoginNoticeDialog_MouseWheel;

        setSort(true);

        NameLabel = new MirLabel();
        NameLabel->setText("");
        NameLabel->setParent(this);
        Font tempVar2(Settings::FontName, 10.0F, FontStyle::Bold);
        NameLabel->setFont(&tempVar2);
        NameLabel->setForeColour(Color::BurlyWood);
        Point tempVar3(30, 6);
        NameLabel->setLocation(&tempVar3);
        NameLabel->setAutoSize(true);

        CloseButton = new MirButton();
        CloseButton->setIndex(360);
        CloseButton->setHoverIndex(361);
        CloseButton->setPressedIndex(362);
        CloseButton->setLibrary(Libraries::Prguse2);
        CloseButton->setParent(this);
        Point tempVar4(289, 3);
        CloseButton->setLocation(&tempVar4);
        CloseButton->setSound(SoundList::ButtonA);
        CloseButton->Click += [&] (o, e)
        {
            Hide();
        };

        OkButton = new MirButton();
        OkButton->setEnabled(true);
        OkButton->setHoverIndex(194);
        OkButton->setIndex(193);
        OkButton->setLibrary(Libraries::Title);
        Point tempVar5(120, 436);
        OkButton->setLocation(&tempVar5);
        OkButton->setParent(this);
        OkButton->setPressedIndex(195);
        OkButton->Click += [&] (o, e)
        {
            Hide();
        };

        UpButton = new MirButton();
        UpButton->setIndex(470);
        UpButton->setHoverIndex(471);
        UpButton->setPressedIndex(472);
        UpButton->setLibrary(Libraries::Prguse2);
        UpButton->setParent(this);
        Size tempVar6(16, 14);
        UpButton->setSize(&tempVar6);
        Point tempVar7(293, 33);
        UpButton->setLocation(&tempVar7);
        UpButton->setSound(SoundList::ButtonA);
        UpButton->setVisible(false);
        UpButton->Click += [&] (o, e)
        {
            if (_index <= 0)
            {
                return;
            }
    
            _index--;
    
            NewText(CurrentLines, false);
            UpdatePositionBar();
        };

        DownButton = new MirButton();
        DownButton->setIndex(473);
        DownButton->setHoverIndex(474);
        DownButton->setLibrary(Libraries::Prguse2);
        DownButton->setPressedIndex(475);
        DownButton->setParent(this);
        Size tempVar8(16, 14);
        DownButton->setSize(&tempVar8);
        Point tempVar9(293, 418);
        DownButton->setLocation(&tempVar9);
        DownButton->setSound(SoundList::ButtonA);
        DownButton->setVisible(true);
        DownButton->Click += [&] (o, e)
        {
            if (_index + MaximumLines >= CurrentLines.size())
            {
                return;
            }
    
            _index++;
    
            NewText(CurrentLines, false);
            UpdatePositionBar();
        };

        PositionBar = new MirButton();
        PositionBar->setIndex(205);
        PositionBar->setHoverIndex(206);
        PositionBar->setPressedIndex(206);
        PositionBar->setLibrary(Libraries::Prguse2);
        Point tempVar10(293, 46);
        PositionBar->setLocation(&tempVar10);
        PositionBar->setParent(this);
        PositionBar->setMovable(true);
        PositionBar->setSound(SoundList::None);
        PositionBar->setVisible(true);
        PositionBar->OnMoving->addListener("PositionBar_OnMoving", std::bind(&NoticeDialog::PositionBar_OnMoving, this, std::placeholders::_1, std::placeholders::_2));
    }

    void NoticeDialog::PositionBar_OnMoving(std::any sender, MouseEventArgs *e)
    {
        int x = 293;
        int y = PositionBar->getLocation()->Y;

        if (y >= 399)
        {
            y = 399;
        }
        if (y <= 46)
        {
            y = 46;
        }

        int location = y - 46;
        int interval = 400 / (CurrentLines.size() - MaximumLines);

        double yPoint = location / interval;

        _index = static_cast<short>(std::floor(yPoint));

        NewText(CurrentLines, false);

        Point tempVar(x, y);
        PositionBar->setLocation(&tempVar);
    }

    void NoticeDialog::LoginNoticeDialog_MouseWheel(std::any sender, MouseEventArgs *e)
    {
        int count = e->Delta / SystemInformation::MouseWheelScrollDelta;

        if (_index == 0 && count >= 0)
        {
            return;
        }
        if (_index == CurrentLines.size() - 1 && count <= 0)
        {
            return;
        }
        if (CurrentLines.size() <= MaximumLines)
        {
            return;
        }

        _index -= count;

        if (_index < 0)
        {
            _index = 0;
        }
        if (_index + MaximumLines > CurrentLines.size() - 1)
        {
            _index = CurrentLines.size() - MaximumLines;
        }

        NewText(CurrentLines, false);

        UpdatePositionBar();
    }

    void NoticeDialog::UpdatePositionBar()
    {
        if (CurrentLines.size() <= MaximumLines)
        {
            return;
        }

        int interval = 400 / (CurrentLines.size() - MaximumLines);

        int x = 293;
        int y = 46 + (_index * interval);

        if (y >= 399)
        {
            y = 399;
        }
        if (y <= 46)
        {
            y = 46;
        }

        Point tempVar(x, y);
        PositionBar->setLocation(&tempVar);
    }

    void NoticeDialog::Update(Notice *notice)
    {
        this->Notice = notice;

        std::vector<std::string> temp;

        if (StringHelper::isEmptyOrWhiteSpace(notice->Message))
        {
            return;
        }

        std::vector<std::string> lines = notice->Message.Split({"\r\n"}, StringSplitOptions::None);

        for (auto line : lines)
        {
            temp.push_back(line);
        }

        NewText(temp);
        setVisible(true);
    }

    void NoticeDialog::NewText(std::vector<std::string> &lines, bool resetIndex)
    {
        if (resetIndex)
        {
            _index = 0;
            CurrentLines = lines;
            UpdatePositionBar();
        }

        if (resetIndex)
        {
            if (getIndex() != -1)
            {
                MaximumLines = 19;
                if (lines.size() > MaximumLines)
                {
                    UpButton->setVisible(true);
                    DownButton->setVisible(true);
                    PositionBar->setVisible(true);
                }
                else
                {
                    UpButton->setVisible(false);
                    DownButton->setVisible(false);
                    PositionBar->setVisible(false);
                }
            }
            else
            {
                MaximumLines = 19;
                UpButton->setVisible(false);
                DownButton->setVisible(false);
                PositionBar->setVisible(false);
            }
        }

        for (int i = 0; i < TextButtons.size(); i++)
        {
            TextButtons[i]->Dispose();
        }

        for (int i = 0; i < TextLabel.size(); i++)
        {
            if (TextLabel[i] != nullptr)
            {
                TextLabel[i]->setText("");
            }
        }

        TextButtons.clear();

        if (!Notice->Title.empty())
        {
            NameLabel->setText(Notice->Title);
        }

        int lastLine = lines.size() > MaximumLines ? ((MaximumLines + _index) > lines.size() ? lines.size() : (MaximumLines + _index)) : lines.size();

        for (int i = _index; i < lastLine; i++)
        {
            MirLabel *tempVar = new MirLabel();
            tempVar->setFont(font);
            tempVar->setDrawFormat(TextFormatFlags::WordBreak);
            tempVar->setVisible(true);
            tempVar->setParent(this);
            Size tempVar2(420, 20);
            tempVar->setSize(&tempVar2);
            Point tempVar3(25, 50 + (i - _index) * 20);
            tempVar->setLocation(&tempVar3);
            tempVar->setNotControl(true);
            TextLabel[i] = tempVar;

            if (i >= lines.size())
            {
                TextLabel[i]->setText("");

                delete tempVar;
                continue;
            }

            std::string currentLine = lines[i];

            std::vector<Match*> matchList = C->Matches(currentLine)->Cast<Match*>().ToList();
            matchList.AddRange(L->Matches(currentLine)->Cast<Match*>());

            int oldLength = currentLine.length();

            for (auto match : matchList.OrderBy([&] (std::any o)
            {
                return o::Index;
            }).ToList())
            {
                int offSet = oldLength - currentLine.length();

                Capture *capture = match::Groups[1].Captures[0];
                std::string txt = match::Groups[2].Captures[0]->Value;
                std::string action = match::Groups[3].Captures[0]->Value;

//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to the .NET String 'Insert' method unless assigning to the string instance:
                currentLine.erase(capture->Index - 1 - offSet, capture->Length + 2)->Insert(capture->Index - 1 - offSet, txt);
                std::string text = currentLine.substr(0, capture->Index - 1 - offSet) + " ";
                Size *size = TextRenderer::MeasureText(CMain::Graphics, text, TextLabel[i]->getFont(), TextLabel[i]->getSize(), TextFormatFlags::TextBoxControl);

                if (L->Match(match->Value)->Success)
                {
                    Point tempVar4(size->Width - 11, 0);
                    NewLink(txt, action, Functions::Add(TextLabel[i]->getLocation(), &tempVar4));
                }

                if (C->Match(match->Value)->Success)
                {
                    Point tempVar5(size->Width - 11, 0);
                    NewColour(txt, action, Functions::Add(TextLabel[i]->getLocation(), &tempVar5));
                }
            }

            TextLabel[i]->setText(currentLine);
            TextLabel[i]->MouseWheel += LoginNoticeDialog_MouseWheel;

            delete tempVar;
        }
        OkButton->BringToFront();
    }

    void NoticeDialog::NewLink(const std::string &text, const std::string &link, Point *p)
    {
        MirLabel *temp = new MirLabel();
        temp->setAutoSize(true);
        temp->setVisible(true);
        temp->setParent(this);
        temp->setLocation(p);
        temp->setText(text);
        temp->setForeColour(Color::Yellow);
        temp->setSound(SoundList::ButtonC);
        temp->setFont(font);


        temp->MouseEnter += [&] (o, e)
        {
            temp->setForeColour(Color::Red);
        };
        temp->MouseLeave += [&] (o, e)
        {
            temp->setForeColour(Color::Yellow);
        };
        temp->MouseDown += [&] (o, e)
        {
            temp->setForeColour(Color::Yellow);
        };
        temp->MouseUp->addListener([&] (o, e)
        {
            temp->setForeColour(Color::Red);
        });

        temp->Click += [&] (o, e)
        {
            if (link.StartsWith("http://", true, CultureInfo::InvariantCulture))
            {
                System::Diagnostics::Process::Start(link);
            }
        };
        temp->MouseWheel += LoginNoticeDialog_MouseWheel;

        TextButtons.push_back(temp);

//C# TO C++ CONVERTER TODO TASK: A 'delete temp' statement was not added since temp was passed to a method or constructor. Handle memory management manually.
    }

    void NoticeDialog::NewColour(const std::string &text, const std::string &colour, Point *p)
    {
        Color *textColour = Color::FromName(colour);

        MirLabel *temp = new MirLabel();
        temp->setAutoSize(true);
        temp->setVisible(true);
        temp->setParent(this);
        temp->setLocation(p);
        temp->setText(text);
        temp->setForeColour(textColour);
        temp->setFont(font);
        temp->MouseWheel += LoginNoticeDialog_MouseWheel;

        TextButtons.push_back(temp);

//C# TO C++ CONVERTER TODO TASK: A 'delete temp' statement was not added since temp was passed to a method or constructor. Handle memory management manually.
    }
}
